libobs_wrapper\scenes\scene_item/
mod.rs1mod traits;
4pub use traits::SceneItemExtSceneTrait;
5
6use std::{fmt::Debug, hash::Hash, sync::Arc};
7
8use libobs::{obs_scene_item, obs_transform_info, obs_video_info};
9
10use crate::{
11 enums::ObsBoundsType,
12 graphics::Vec2,
13 impl_obs_drop,
14 macros::trait_with_optional_send_sync,
15 run_with_obs,
16 runtime::ObsRuntime,
17 scenes::{ObsSceneRef, ObsTransformInfo, ObsTransformInfoBuilder},
18 sources::ObsSourceTrait,
19 unsafe_send::{Sendable, SmartPointerSendable},
20 utils::{ObsDropGuard, ObsError},
21};
22
23#[derive(Debug)]
24pub(super) struct _ObsSceneItemDropGuard {
25 scene_item: Sendable<*mut obs_scene_item>,
26 runtime: ObsRuntime,
27}
28
29impl ObsDropGuard for _ObsSceneItemDropGuard {}
30impl_obs_drop!(_ObsSceneItemDropGuard, (scene_item), move || unsafe {
31 libobs::obs_sceneitem_remove(scene_item.0);
34 });
36
37#[derive(Debug, Clone)]
38pub struct ObsSceneItemRef<T: ObsSourceTrait + Clone> {
42 scene_item_ptr: SmartPointerSendable<*mut obs_scene_item>,
44 runtime: ObsRuntime,
45 _scene_ptr: SmartPointerSendable<*mut libobs::obs_scene>,
52
53 underlying_source: T,
55}
56
57impl<T: ObsSourceTrait + Clone> ObsSceneItemRef<T> {
58 pub(crate) fn new(
59 scene: &ObsSceneRef,
60 source: T,
61 runtime: ObsRuntime,
62 ) -> Result<Self, ObsError> {
63 let scene_ptr = scene.as_ptr();
64 let source_ptr = source.as_ptr();
65
66 let scene_item_ptr = run_with_obs!(runtime, (scene_ptr, source_ptr), move || {
67 let ptr = unsafe {
68 libobs::obs_scene_add(scene_ptr.get_ptr(), source_ptr.get_ptr())
70 };
71
72 if ptr.is_null() {
73 Err(ObsError::NullPointer(None))
74 } else {
75 Ok(Sendable(ptr))
76 }
77 })??;
78
79 let drop_guard = _ObsSceneItemDropGuard {
80 scene_item: scene_item_ptr.clone(),
81 runtime: runtime.clone(),
82 };
83
84 let scene_item_ptr = SmartPointerSendable::new(scene_item_ptr.0, Arc::new(drop_guard));
85
86 Ok(Self {
87 underlying_source: source,
88 _scene_ptr: scene.as_ptr().clone(),
89 scene_item_ptr,
90 runtime,
91 })
92 }
93}
94
95trait_with_optional_send_sync! {
96 pub trait SceneItemTrait: Debug {
97 fn as_ptr(&self) -> &SmartPointerSendable<*mut obs_scene_item>;
98 fn runtime(&self) -> ObsRuntime;
99 fn inner_source_dyn(&self) -> &dyn ObsSourceTrait;
100 fn inner_source_dyn_mut(&mut self) -> &mut dyn ObsSourceTrait;
101
102 fn get_transform_info(&self) -> Result<ObsTransformInfo, ObsError> {
104 let self_ptr = self.as_ptr();
105 let item_info = run_with_obs!(self.runtime(), (self_ptr), move || {
106 let mut item_info: obs_transform_info = unsafe {
107 std::mem::zeroed()
109 };
110 unsafe {
111 libobs::obs_sceneitem_get_info2(self_ptr.get_ptr(), &mut item_info)
113 };
114
115 ObsTransformInfo(item_info)
116 })?;
117
118 Ok(item_info)
119 }
120
121 fn get_source_position(&self) -> Result<Vec2, ObsError> {
123 let self_ptr = self.as_ptr();
124 let position = run_with_obs!(self.runtime(), (self_ptr), move || {
125 let main_pos = unsafe {
126 let mut main_pos: libobs::vec2 = std::mem::zeroed();
128
129 libobs::obs_sceneitem_get_pos(self_ptr.get_ptr(), &mut main_pos);
131
132 main_pos
133 };
134
135 Vec2::from(main_pos)
136 })?;
137
138 Ok(position)
139 }
140
141 fn get_source_scale(&self) -> Result<Vec2, ObsError> {
143 let self_ptr = self.as_ptr();
144 let scale = run_with_obs!(self.runtime(), (self_ptr), move || {
145 let main_pos = unsafe {
146 let mut main_pos: libobs::vec2 = std::mem::zeroed();
148
149 libobs::obs_sceneitem_get_scale(self_ptr.get_ptr(), &mut main_pos);
151
152 main_pos
153 };
154
155 Vec2::from(main_pos)
156 })?;
157
158 Ok(scale)
159 }
160
161 fn set_source_position(&self, position: Vec2) -> Result<(), ObsError> {
163 let self_ptr = self.as_ptr();
164
165 run_with_obs!(self.runtime(), (self_ptr), move || {
166 let position: libobs::vec2 = position.into();
167
168 unsafe {
169 libobs::obs_sceneitem_set_pos(self_ptr.get_ptr(), &position);
171 }
172 })?;
173
174 Ok(())
175 }
176
177 fn set_transform_info(&self, info: &ObsTransformInfo) -> Result<(), ObsError> {
180 let item_info = Sendable(info.clone());
181 let self_ptr = self.as_ptr();
182
183 run_with_obs!(self.runtime(), (self_ptr, item_info), move || {
184 let item_info = item_info.0 .0;
185
186 unsafe {
187 libobs::obs_sceneitem_set_info2(self_ptr.get_ptr(), &item_info);
189 }
190 })?;
191
192 Ok(())
193 }
194
195 fn fit_source_to_screen(&self) -> Result<bool, ObsError> {
200 let self_ptr = self.as_ptr();
201 let is_locked = {
202 run_with_obs!(self.runtime(), (self_ptr), move || unsafe {
203 libobs::obs_sceneitem_locked(self_ptr.get_ptr())
205 })?
206 };
207
208 if is_locked {
209 return Ok(false);
210 }
211
212 let ovi = run_with_obs!(self.runtime(), (), move || {
213 let mut ovi = std::mem::MaybeUninit::<obs_video_info>::uninit();
214 let success = unsafe {
215 libobs::obs_get_video_info(ovi.as_mut_ptr())
217 };
218
219 if success {
220 let res = unsafe {
221 ovi.assume_init()
223 };
224
225 Ok(Sendable(res))
226 } else {
227 Err(ObsError::NullPointer(Some(
228 "Failed to get video info".to_string(),
229 )))
230 }
231 })??;
232
233 let bounds_crop = run_with_obs!(self.runtime(), (self_ptr), move || {
234 unsafe {
235 libobs::obs_sceneitem_get_bounds_crop(self_ptr.get_ptr())
237 }
238 })?;
239
240 let item_info = ObsTransformInfoBuilder::new()
242 .set_bounds_type(ObsBoundsType::ScaleInner)
243 .set_crop_to_bounds(bounds_crop)
244 .build(ovi.0.base_width, ovi.0.base_height);
245
246 self.set_transform_info(&item_info)?;
247 Ok(true)
248 }
249
250 fn set_source_scale(&self, scale: Vec2) -> Result<(), ObsError> {
252 let self_ptr = self.as_ptr();
253
254 run_with_obs!(self.runtime(), (self_ptr), move || {
255 let scale: libobs::vec2 = scale.into();
256
257 unsafe {
258 libobs::obs_sceneitem_set_scale(self_ptr.get_ptr(), &scale);
260 }
261 })?;
262
263 Ok(())
264 }
265 }
266}
267
268impl<T: ObsSourceTrait + Clone> SceneItemTrait for ObsSceneItemRef<T> {
269 fn as_ptr(&self) -> &SmartPointerSendable<*mut obs_scene_item> {
270 &self.scene_item_ptr
271 }
272
273 fn runtime(&self) -> ObsRuntime {
274 self.runtime.clone()
275 }
276
277 fn inner_source_dyn(&self) -> &dyn ObsSourceTrait {
278 &self.underlying_source
279 }
280
281 fn inner_source_dyn_mut(&mut self) -> &mut dyn ObsSourceTrait {
282 &mut self.underlying_source
283 }
284}
285
286impl<T> ObsSceneItemRef<T>
287where
288 T: ObsSourceTrait + Clone,
289{
290 pub fn inner_source(&self) -> &T {
292 &self.underlying_source
293 }
294
295 pub fn inner_source_mut(&mut self) -> &mut T {
297 &mut self.underlying_source
298 }
299}
300
301impl<T: ObsSourceTrait + Clone> PartialEq for ObsSceneItemRef<T> {
305 fn eq(&self, other: &Self) -> bool {
306 self.scene_item_ptr.get_ptr() == other.scene_item_ptr.get_ptr()
307 }
308}
309
310impl<T: ObsSourceTrait + Clone> Eq for ObsSceneItemRef<T> {}
311
312impl<T: ObsSourceTrait + Clone> Hash for ObsSceneItemRef<T> {
313 fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
314 self.scene_item_ptr.get_ptr().hash(state);
315 }
316}